package com.example.customview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.InputFilter;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.inputmethod.InputMethodManager;

import androidx.appcompat.widget.AppCompatEditText;

/**
 * 验证码输入框,重写EditText的绘制方法实现。
 */
public class CodeEditText extends AppCompatEditText {
    private int textColor;          // 验证码文本颜色
    private int maxLength = 4;      // 输入的最大长度
    private int strokeWidth;        // 边框宽度
    private int strokeHeight;       // 边框高度
    private int strokePadding = 20; // 边框之间的距离
    private final Rect rect = new Rect();   // 用矩形保存方框的位置、大小信息
    private Drawable strokeDrawable;        // 方框背景
    private OnTextFinishListener finishListener;  // 输入结束监听器

    /**
     * 构造方法，初始化输入框大小、边框大小及间距以及验证码个数等基本参数
     *
     * @param context 上下文
     * @param attrs   属性集合
     */
    public CodeEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.CodeEditText);
        int indexCount = typedArray.getIndexCount();
        for (int i = 0; i < indexCount; i++) {
            int index = typedArray.getIndex(i);
            if (index == R.styleable.CodeEditText_strokeHeight) {
                this.strokeHeight = (int) typedArray.getDimension(index, 60);
            } else if (index == R.styleable.CodeEditText_strokeWidth) {
                this.strokeWidth = (int) typedArray.getDimension(index, 60);
            } else if (index == R.styleable.CodeEditText_strokePadding) {
                this.strokePadding = (int) typedArray.getDimension(index, 20);
            } else if (index == R.styleable.CodeEditText_strokeBackground) {
                this.strokeDrawable = typedArray.getDrawable(index);
            } else if (index == R.styleable.CodeEditText_strokeLength) {
                this.maxLength = typedArray.getInteger(index, 4);
            }
        }
        typedArray.recycle();

        if (strokeDrawable == null) {
            throw new NullPointerException("strokeDrawable对象不能为空!");
        }
        // 设置最大长度
        setMaxLength(maxLength);
        // 禁止长按操作
        setLongClickable(false);
        // 去掉背景颜色
        setBackgroundColor(Color.TRANSPARENT);
        // 不显示光标
        setCursorVisible(false);
    }

    /**
     * 设置最大长度
     *
     * @param maxLength 验证码个数
     */
    private void setMaxLength(int maxLength) {
        if (maxLength >= 0) {
            setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
        } else {
            setFilters(new InputFilter[0]);
        }
    }

    @Override
    public boolean onTextContextMenuItem(int id) {
        return false;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 当前输入框的宽高信息
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        // 判断高度是否小于推荐高度
        if (height < strokeHeight) {
            height = strokeHeight;
        }
        // 输入框宽度 = 边框宽度 * 数量 + 边框间距 *(数量-1)
        int recommendWidth = strokeWidth * maxLength + strokePadding * (maxLength - 1);
        // 判断宽度是否小于推荐宽度
        if (width < recommendWidth) {
            width = recommendWidth;
        }
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, widthMode);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, heightMode);
        // 设置测量布局
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 把系统的文本颜色设为透明
        textColor = getCurrentTextColor();
        setTextColor(Color.TRANSPARENT);

        super.onDraw(canvas);
        // 重置文本颜色
        setTextColor(textColor);
        // 重绘输入框
        drawStrokeBackground(canvas);
        // 重绘文本
        drawText(canvas);
    }

    /**
     * 绘制方框
     * @param canvas 画布对象
     */
    private void drawStrokeBackground(Canvas canvas) {
        // 下面绘制方框背景颜色
        // 确定反馈位置
        rect.left = 0;
        rect.top = 0;
        rect.right = strokeWidth;
        rect.bottom = strokeHeight;
        int count = canvas.getSaveCount(); // 当前画布保存的状态
        canvas.save(); // 保存画布

        // 绘制每个输入框
        for (int i = 0; i < maxLength; i++) {
            strokeDrawable.setBounds(rect); // 设置位置
            strokeDrawable.setState(new int[]{android.R.attr.state_enabled}); // 设置图像状态
            strokeDrawable.draw(canvas); // 画到画布上
            // 确定下一个方框的位置
            float dx = rect.right + strokePadding; // X坐标位置
            // 保存画布
            canvas.save();
            // 移动画布到下一个位置
            canvas.translate(dx, 0);
        }
        // 把画布还原到画反馈之前的状态，这样就还原到最初位置了
        canvas.restoreToCount(count);
        // 画布归位
        canvas.translate(0, 0);

        // 绘制高亮状态的边框
        int activatedIndex = Math.max(0, getEditableText().length());
        rect.left = strokeWidth * activatedIndex + strokePadding * activatedIndex;
        rect.right = rect.left + strokeWidth;
        strokeDrawable.setState(new int[]{android.R.attr.state_focused});
        strokeDrawable.setBounds(rect);
        strokeDrawable.draw(canvas);
    }

    /**
     * 重绘文本
     * @param canvas 画布对象
     */
    private void drawText(Canvas canvas) {
        int count = canvas.getSaveCount();
        canvas.translate(0, 0);

        int length = getEditableText().length();
        for (int i = 0; i < length; i++) {
            String text = String.valueOf(getEditableText().charAt(i));
            TextPaint textPaint = getPaint();
            textPaint.setColor(textColor);
            // 获取文本大小
            textPaint.getTextBounds(text, 0, 1, rect);
            // 计算(x,y) 坐标
            int x = strokeWidth / 2 + (strokeWidth + strokePadding) * i - (rect.centerX());
            int y = canvas.getHeight() / 2 + rect.height() / 2;
            canvas.drawText(text, x, y, textPaint);
        }
        canvas.restoreToCount(count);
    }

    @Override
    protected void onTextChanged(CharSequence text, int start,
                                 int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        // 当前文本长度
        int textLength = getEditableText().length();
        if (textLength == maxLength) {
            hideSoftInput();
            if (finishListener != null) {
                finishListener.onTextFinish(getEditableText().toString(), maxLength);
            }
        }
    }

    /**
     * 关闭软键盘
     */
    public void hideSoftInput() {
        InputMethodManager imm = (InputMethodManager) getContext()
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null)
            imm.hideSoftInputFromWindow(getWindowToken(),
                    InputMethodManager.HIDE_NOT_ALWAYS);
    }

    /**
     * 设置输入完成监听
     */
    public void setOnTextFinishListener(OnTextFinishListener finishListener) {
        this.finishListener = finishListener;
    }

    /**
     * 文本输入完成的监听事件
     */
    public interface OnTextFinishListener {
        void onTextFinish(CharSequence text, int length);
    }
}